﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Numerics;
using System.Reflection;
using System.Drawing;
using ArgusLib.Xml;
using ArgusLib.Drawing;

namespace ArgusLib.Fractals.OrbitFractals
{
	public class RendererEscapeTime : Renderer<IDataSetIterations, RenderParameterEscapeTime>
	{
		delegate Color ColorProvider(int iterations);

		#region Constructors
		public RendererEscapeTime(RenderParameterEscapeTime parameter)
			: base(parameter) { }
		#endregion

		#region Public Methods
		public override IDataSetProvider GetCompatibleDataSetProvider()
		{
			return new DataSetComplexProvider();
		}

		protected override void RenderCore(ExtendedBitmap image, IDataSet dataSet)
		{
			IDataSetIterations dSet = (IDataSetIterations)dataSet;
			image.Fill(this.Parameter.BackgroundColor);

			ColorProvider colorProvider = this.GetColorProvider();

			for (int x = 0; x < image.Width; x++)
			{
				for (int y = 0; y < image.Height; y++)
				{
					if (dataSet.IsNull[x, y] == true || dSet.Iterations[x, y] >= dSet.CalculationParameter.Iterations)
					{
						image.BlendPixel(x, y, this.Parameter.SetColor);
					}
					else
					{
						Color c = colorProvider(dSet.Iterations[x, y]);
						image.BlendPixel(x, y, c);
					}
				}
			}
		}
		#endregion

		#region Non-Public Methods
		private ColorProvider GetColorProvider()
		{
			Type type = typeof(RendererEscapeTime);
			MethodInfo mi = type.GetMethod("ColorProvider_" + this.Parameter.Coloring.ToString(), BindingFlags.NonPublic | BindingFlags.Static);
			if (mi == null)
				return null;
			else
				return Delegate.CreateDelegate(typeof(ColorProvider), mi) as ColorProvider;
		}
		#endregion

		#region ColorProvider Methods
		private static Color ColorProvider_RedYellow(int iterations)
		{
			byte[] b = GetColorBytes_2(iterations);
			return Color.FromArgb(255, b[0], b[1], 0);
		}

		private static Color ColorProvider_BlueTurquoise(int iterations)
		{
			byte[] a = GetColorBytes_2(iterations);
			return Color.FromArgb(255, 0, a[1], a[0]);
		}

		private static Color ColorProvider_GreenYellow(int iterations)
		{
			byte[] a = GetColorBytes_2(iterations);
			return Color.FromArgb(255, a[1], a[0], 0);
		}

		private static Color ColorProvider_Red(int iterations)
		{
			byte[] a = GetColorBytes_2(iterations);
			return Color.FromArgb((byte)(255 - a[1]), a[0], 0, 0);
		}

		private static Color ColorProvider_Blue(int iterations)
		{
			byte[] a = GetColorBytes_2(iterations);
			return Color.FromArgb((byte)(255 - a[1]), 0, 0, a[0]);
		}

		private static Color ColorProvider_Green(int iterations)
		{
			byte[] a = GetColorBytes_2(iterations);
			return Color.FromArgb((byte)(255 - a[1]), 0, a[0], 0);
		}

		private static Color ColorProvider_Violette(int iterations)
		{
			byte[] a = GetColorBytes_2(iterations);
			return Color.FromArgb((byte)(255 - a[1]), (byte)((a[0] + a[1]) / 2), 0, (byte)((a[0] + a[1]) / 2));
		}

		private static Color ColorProvider_Yellow(int iterations)
		{
			byte[] a = GetColorBytes_2(iterations);
			return Color.FromArgb((byte)(255 - a[1]), (byte)((a[0] + a[1]) / 2), (byte)((a[0] + a[1]) / 2), 0);
		}

		private static Color ColorProvider_Turquoise(int iterations)
		{
			byte[] a = GetColorBytes_2(iterations);
			return Color.FromArgb((byte)(255 - a[1]), 0, (byte)((a[0] + a[1]) / 2), (byte)((a[0] + a[1]) / 2));
		}

		private static Color ColorProvider_RedGreenBlue(int iterations)
		{
			byte[] a = GetColorBytes_3(iterations);
			return Color.FromArgb(255, a[0], a[1], a[2]);
		}

		private static Color ColorProvider_GreenBlueRed(int iterations)
		{
			byte[] a = GetColorBytes_3(iterations);
			return Color.FromArgb(255, a[1], a[2], a[0]);
		}

		private static Color ColorProvider_BlueRedGreen(int iterations)
		{
			byte[] a = GetColorBytes_3(iterations);
			return Color.FromArgb(255, a[2], a[0], a[1]);
		}

		private static byte[] GetColorBytes_2(Int32 i)
		{
			byte a = 0;
			byte b = 0;
			if (i < 16)
				a = (byte)((i) * 16 + 15);
			else
			{
				if (i < 11)
					a = (byte)(i * 25);
				else
				{
					if (i > 4 * 16)
						i = i % (4 * 16);

					if (i < 16)
						a = (byte)((i + 1) * 16 - 1);
					else if (i < 2 * 16)
					{
						a = 255;
						i = i - 16;
						b = (byte)((i + 1) * 16 - 1);
					}
					else if (i < 3 * 16)
					{
						a = 255;
						i = i - 2 * 16;
						b = (byte)(255 - ((i + 1) * 16 - 1));
					}
					else if (i < 4 * 16)
					{
						i = i - 3 * 16;
						a = (byte)(255 - ((i + 1) * 16 - 1));
					}
				}
			}
			return new byte[] { a, b };
		}

		private static byte[] GetColorBytes_3(Int32 i)
		{
			byte a, b, c;
			a = b = c = 0;

			if (i < 11)
				a = (byte)(i * 25);
			else
			{
				if (i > 8 * 16)
					i = i % (8 * 16);

				if (i < 16)
					a = (byte)((i + 1) * 16 - 1);
				else if (i < 2 * 16)
				{
					a = 255;
					i = i - 16;
					b = (byte)((i + 1) * 16 - 1);
				}
				else if (i < 3 * 16)
				{
					a = 255;
					i = i - 2 * 16;
					b = (byte)(255 - ((i + 1) * 16 - 1));
				}
				else if (i < 4 * 16)
				{
					i = i - 3 * 16;
					a = (byte)(255 - ((i + 1) * 16 - 1));
				}
				else if (i < 5 * 16)
				{
					i = i - 4 * 16;
					b = (byte)((i + 1) * 16 - 1);
				}
				else if (i < 6 * 16)
				{
					b = 255;
					i = i - 5 * 16;
					c = (byte)((i + 1) * 16 - 1);
				}
				else if (i < 7 * 16)
				{
					b = 255;
					i = i - 6 * 16;
					c = (byte)(255 - ((i + 1) * 16 - 1));
				}
				else if (i < 8 * 16)
				{
					i = i - 7 * 16;
					b = (byte)(255 - ((i + 1) * 16 - 1));
				}
			}
			return new byte[] { a, b, c };
		}
		#endregion
	}
}
